package ronin.scene;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.Vector;
import ronin.actor2d.*;
import java.util.LinkedList;

/**
 * The Class QuadScene.
 */
public class QuadScene extends Scene {
    
    /**
     * Unit Types allow you to tag each actor as you add them to the scene. 
     * This allows functions like getUnits(theUnitType), 
     * getUnitsInRange(theUnitType, Rectangle2D bounds) etc to differentiate 
     * between units in the scene.
     */
    public static final int UNIT_TYPE_WALL 		= 10001;
    public static final int UNIT_TYPE_DOOR		= 100001;
    public static final int UNIT_TYPE_OBSTACLE	= 1000001;
    public static final int UNIT_TYPE_ACTOR		= 10000001;
    
    public LinkedList<Actor2D> listOfWalls,listOfDoors, listOfObstacles, listOfActors; 
    
    /** 
     * The QuadTree is used mainly for collision detection. All elements added to the scene
     * are automatically added to the tree. The scene will update and render the viewable
     * contents of the tree by default. 
     * */
    protected static QuadTree tree;

    /** 
     * The mainApp variable represents the application that has created this 
     * scene usually. If for some reason another Applet needs to be sent, maybe
     * for resource loading etc. Doesn't serve a purpose now, but is left 
     * for future use. 
     * */
    protected static Applet mainApp; 

    /** The color of the tree, used when the node borders need to be drawn. */
    protected static final Color treeColor = new Color(139, 23, 255);

    /** 
     * The debug value simply designates whether the 'QuadTree' borders will
     * be drawn. 
     */
    public boolean debug;

    /**
     * Instantiates a new quad scene.
     * 
     * @param a the a
     * @param depth the depth
     * @param b the b
     * @param v the v
     * @param debugOn the debug on
     */
    public QuadScene(Applet a, int depth, Rectangle2D b, Rectangle2D v, boolean debugOn) {
		super(b, v);

		mainApp = a;
		
		debug = debugOn;
		
		tree = new QuadTree(depth, b, this, debug);
		
		listOfActors = new LinkedList<Actor2D>();
		listOfDoors  = new LinkedList<Actor2D>();
		listOfObstacles = new LinkedList<Actor2D>();
		listOfWalls = new LinkedList<Actor2D>();
	
    }

    /**
     * adds an Actor2D object to the scene.
     * @see ronin.scene.Scene#add(ronin.actor2d.Actor2D)
     */
    public void add(Actor2D a) {
		tree.insert(a);
    }
    
    public void add(Actor2D a, int unitType){
    	
    	// overide actor internal unit type variable for use with this scene.
    	a.unitType = unitType;
    	
    	// add it one of the unitType listOf whatever
    	switch (a.unitType) 
    	{
    		case UNIT_TYPE_ACTOR: listOfActors.add(a); break;
    		case UNIT_TYPE_DOOR: listOfDoors.add(a); break;
    		case UNIT_TYPE_OBSTACLE: listOfObstacles.add(a); break;
    		case UNIT_TYPE_WALL: listOfWalls.add(a); break;
    		default : break;
		}
		
		// go on and add it to the tree now!
    	add(a);
    }

    /**
     * Paints the contents of the Tree normally and if debug enabled
     * paints the borders of each node. 
     * 
     * @see ronin.scene.Scene#paint(java.awt.Graphics2D)
     */
    public void paint(Graphics2D g) {
		tree.paint(g);

		if (debug == true) {
	    	tree.paintBounds(g, treeColor);
		}
    }

    /**
     * Updates the entire contents of tree.
     * 
     * @see ronin.scene.Scene#update()
     */
    public void update() {
		tree.update();
    }

	public boolean checkForCollision(Rectangle2D area){
			
		if(tree.checkForCollision(area)) return true;
		
		return false;
	}
	
	public Vector findCollisionsWith(Actor2D actor){
		
		Vector collisionHolder = tree.findCollisionsWith(actor);
		
		if( collisionHolder == null || collisionHolder.size() == 0 ) return null;
		
		return collisionHolder;
	}
	
	public LinkedList getWalls(){
		return listOfWalls;
	}
	
	public LinkedList getDoors(){
		return listOfDoors;
	}
	
	public LinkedList getActors(){
		return listOfActors;
	}
	
	public LinkedList getObstacles(){
		return listOfObstacles;
	}
}